package com.hotel.gateway.filter;

import com.hotel.common.utils.Result;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.ReactiveRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import javax.crypto.SecretKey;

@Component
@Order(-1)
public class AuthGlobalFilter implements GlobalFilter {
    //不想看前端，我需要哆啦A梦的记忆馒头帮我把Vue和react嵌入到我的脑子这样我就可以安心添砖加瓦。
    private static final Logger logger = LoggerFactory.getLogger(AuthGlobalFilter.class);

    @Autowired
    @Qualifier("reactiveStringRedisTemplate")//指定
    private ReactiveRedisTemplate<String, String> redisTemplate;
    
    private final ObjectMapper objectMapper = new ObjectMapper();//toString用来适配result类的lombok的（那边没有重写toString），不然会报错

    @org.springframework.beans.factory.annotation.Value("${jwt.secret:#{null}}")
    private String jwtSecret;

    private SecretKey getKey() {
        if (jwtSecret == null || jwtSecret.length() < 32) {
            throw new IllegalStateException("jwt.secret 未配置或长度不足，需在 Nacos jwt.yaml 提供长度≥32的ASCII密钥");
        }
        return Keys.hmacShaKeyFor(jwtSecret.getBytes(java.nio.charset.StandardCharsets.UTF_8));
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String path = exchange.getRequest().getURI().getPath();
        String method = exchange.getRequest().getMethod() != null ? exchange.getRequest().getMethod().name() : "";
        //我测试代码用的日志，写控制台上让我look
        logger.debug("Gateway filter processing request: {} {}", method, path);
        
        // 放行白名单
        if ("OPTIONS".equalsIgnoreCase(method)
                || "/api/auth/login".equals(path)
                || "/api/auth/register".equals(path)
                || "/api/users/register".equals(path)
                // AI 对话放掉（StripPrefix=1 后路径为 /ai/ask）
                || path.startsWith("/ai/")
                // 前台公开访问：酒店、房间和评价列表（只放行GET）
                || ("GET".equalsIgnoreCase(method) && (path.startsWith("/po/hotels") || path.startsWith("/po/rooms") || path.startsWith("/po/reviews")))) {
            logger.debug("Request {} {} is in whitelist, allowing through", method, path);
            return chain.filter(exchange);
        }
        
        // 获取token
        String authHeader = exchange.getRequest().getHeaders().getFirst("Authorization");
        if (authHeader == null || !authHeader.startsWith("Bearer ")) {
            logger.warn("No valid Authorization header found for request: {} {}", method, path);
            return unauthorized(exchange);
        }
        
        final String token = authHeader.substring(7);
        logger.debug("Extracted token: {}", token);
        
        // 校验JWT签名并解析uid，禁用旧UUID兼容
        final Claims claims;
        try {
            claims = Jwts.parserBuilder().setSigningKey(getKey()).build().parseClaimsJws(token).getBody();
        } catch (Exception e) {
            logger.warn("Invalid JWT: {}", e.getMessage());
            return unauthorized(exchange);
        }

        String uid = String.valueOf(claims.get("uid"));

        String blackKey = "black:" + token;
        return redisTemplate.hasKey(blackKey)
                .flatMap(isBlack -> {
                    if (Boolean.TRUE.equals(isBlack)) {
                        logger.warn("Token is blacklisted: {}", token);
                        return unauthorized(exchange);
                    }
                    ServerWebExchange mutated = exchange.mutate()
                            .request(b -> b.header("X-User-Id", uid))
                            .build();
                    return chain.filter(mutated);
                })
                .onErrorResume(throwable -> {
                    logger.error("Error during token validation for token: {}", token, throwable);
                    return unauthorized(exchange);
                });
    }

    private Mono<Void> unauthorized(ServerWebExchange exchange) {
        try {
            Result<String> result = Result.error("未授权访问");
            String jsonResult = objectMapper.writeValueAsString(result);
            byte[] bytes = jsonResult.getBytes(StandardCharsets.UTF_8);
            
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON);
            
            return exchange.getResponse().writeWith(Mono.just(exchange.getResponse()
                    .bufferFactory().wrap(bytes)));
        } catch (Exception e) {
            // 反序列化问题处理，如果JSON序列化失败，返回简单的错误信息
            String errorJson = "{\"code\":401,\"message\":\"未授权访问\",\"data\":null,\"timestamp\":" + System.currentTimeMillis() + "}";
            byte[] bytes = errorJson.getBytes(StandardCharsets.UTF_8);
            
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON);
            
            return exchange.getResponse().writeWith(Mono.just(exchange.getResponse()
                    .bufferFactory().wrap(bytes)));
        }
    }
}